/**
 * 棋盘
 */
package org.beykery.game.chess.ui;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.event.MouseInputListener;
import org.beykery.game.chess.*;

/**
 *
 * @author c
 */
public class ChessPanel extends javax.swing.JPanel implements MouseInputListener
{

  public static final int BORDERWIDTH = 15;//棋盘(左右)边缘的宽度
  public static final int BORDERHEIGHT = 14; //棋盘(上下)边缘的高度
  public static final int GRILLEWIDTH = 39; //棋盘上每个格子的高度
  public static final int GRILLEHEIGHT = 39;//棋盘上每个格子的宽度
  public static final byte[][] initChessBoard =
  {
    {
      Eveluation.B_CAR, Eveluation.B_HORSE, Eveluation.B_ELEPHANT, Eveluation.B_BISHOP, Eveluation.B_KING, Eveluation.B_BISHOP, Eveluation.B_ELEPHANT, Eveluation.B_HORSE, Eveluation.B_CAR
    },
    {
      Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS
    },
    {
      Eveluation.NOCHESS, Eveluation.B_CANON, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.B_CANON, Eveluation.NOCHESS
    },
    {
      Eveluation.B_PAWN, Eveluation.NOCHESS, Eveluation.B_PAWN, Eveluation.NOCHESS, Eveluation.B_PAWN, Eveluation.NOCHESS, Eveluation.B_PAWN, Eveluation.NOCHESS, Eveluation.B_PAWN
    },
    {
      Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS
    },
    {
      Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS
    },
    {
      Eveluation.R_PAWN, Eveluation.NOCHESS, Eveluation.R_PAWN, Eveluation.NOCHESS, Eveluation.R_PAWN, Eveluation.NOCHESS, Eveluation.R_PAWN, Eveluation.NOCHESS, Eveluation.R_PAWN
    },
    {
      Eveluation.NOCHESS, Eveluation.R_CANON, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.R_CANON, Eveluation.NOCHESS
    },
    {
      Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS, Eveluation.NOCHESS
    },
    {
      Eveluation.R_CAR, Eveluation.R_HORSE, Eveluation.R_ELEPHANT, Eveluation.R_BISHOP, Eveluation.R_KING, Eveluation.R_BISHOP, Eveluation.R_ELEPHANT, Eveluation.R_HORSE, Eveluation.R_CAR
    }
  };
  private static final long serialVersionUID = 1L;
  Image chessmap;
  Image chessman;
  Image[] chessmen;
  SearchEngine se;
  byte[][] chessBoard;
  byte[][] backupChessBoard;
  boolean gameOver = false;//this code does not contents in books.
  private int boardWidth;
  private int boardHeight;
  Point m_ptMoveChess;
  Move m_MoveChess;
  private Eveluation eveluation;
  private MoveGenerator moveGenerator;

  /**
   * Creates new form ChessPanel
   */
  public ChessPanel()
  {
    initComponents();
    init();
    this.addMouseListener(this);
    this.addMouseMotionListener(this);
  }

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setMaximumSize(new java.awt.Dimension(384, 412));
        setMinimumSize(new java.awt.Dimension(384, 412));
        setPreferredSize(new java.awt.Dimension(384, 412));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 412, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables

  @Override
  public void paint(Graphics g)
  {
    Graphics2D g2d = (Graphics2D) g;
    g2d.drawImage(chessmap, 0, 0, null);
    for (int i = 0; i < 10; i++)
    {
      for (int j = 0; j < 9; j++)
      {
        if (chessBoard[i][j] == Eveluation.NOCHESS)
        {
          continue;
        }
        int x = j * GRILLEHEIGHT + BORDERHEIGHT;
        int y = i * GRILLEWIDTH + BORDERWIDTH;
        g2d.drawImage(chessmen[chessBoard[i][j] - 1], x, y, null);
      }
    }
  }

  /**
   * 初始化各个资源
   */
  private void init()
  {
    try
    {
      chessmap = ImageIO.read(ChessPanel.class.getResourceAsStream("bitmap.bmp"));
      chessman = ImageIO.read(ChessPanel.class.getResourceAsStream("chessman.bmp"));
    } catch (IOException ex)
    {
      Logger.getLogger(ChessPanel.class.getName()).log(Level.SEVERE, null, ex);
    }
    this.chessmen = new Image[14];
    for (int i = 0; i < chessmen.length; i++)
    {
      chessmen[i] = new BufferedImage(36, 36, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2d = (Graphics2D) chessmen[i].getGraphics();
      g2d.drawImage(chessman, -i * 36, 0, null);
    }
    /**
     * 初始化引擎
     */
    //this.se = new AlphaBetaEngine();
    //this.se=new AlphaBetaAndHH();
    //this.se=new AlphaBetaAndTT();
    this.se = new NegaScout_TT_HH();
    this.eveluation = new Eveluation();
    this.moveGenerator = new MoveGenerator();
    se.setEveluator(eveluation);
    se.setMoveGenerator(moveGenerator);
    se.setSearchDepth(5);
    this.backupChessBoard = new byte[10][9];
    this.chessBoard = new byte[10][9];
    for (int i = 0; i < chessBoard.length; i++)
    {
      System.arraycopy(initChessBoard[i], 0, chessBoard[i], 0, chessBoard[i].length);
    }
    this.gameOver = false;
    this.boardWidth = this.chessmap.getWidth(null);
    this.boardHeight = this.chessmap.getHeight(null);
    this.m_ptMoveChess = new Point();
    this.m_MoveChess = new Move();
  }

  public static boolean isGameOver(byte[][] position)
  {
    int i, j;
    boolean RedLive = false, BlackLive = false;
    for (i = 7; i < 10; i++)
    {
      for (j = 3; j < 6; j++)
      {
        if (position[i][j] == Eveluation.B_KING)
        {
          BlackLive = true;
        }
        if (position[i][j] == Eveluation.R_KING)
        {
          RedLive = true;
        }
      }
    }
    for (i = 0; i < 3; i++)
    {
      for (j = 3; j < 6; j++)
      {
        if (position[i][j] == Eveluation.B_KING)
        {
          BlackLive = true;
        }
        if (position[i][j] == Eveluation.R_KING)
        {
          RedLive = true;
        }
      }
    }
    if (RedLive && BlackLive)
    {
      return false;
    } else
    {
      return true;
    }
  }

  @Override
  public void mouseClicked(MouseEvent e)
  {
    // throw new UnsupportedOperationException("Not supported yet.");
  }

  @Override
  public void mousePressed(MouseEvent e)
  {
    // TODO: Add your message handler code here and/or call default
    if (this.gameOver)
    {
      return;
    }
    for (int i = 0; i < chessBoard.length; i++)
    {
      System.arraycopy(chessBoard[i], 0, backupChessBoard[i], 0, chessBoard[i].length);
    }
    if (e.getX() > 0 && e.getY() > 0 && e.getX() < boardWidth && e.getY() < boardHeight && MoveGenerator.isRed(chessBoard[(e.getY() - BORDERHEIGHT) / GRILLEHEIGHT][(e.getX() - BORDERWIDTH) / GRILLEWIDTH]))
    {
      for (int i = 0; i < chessBoard.length; i++)
      {
        System.arraycopy(chessBoard[i], 0, backupChessBoard[i], 0, chessBoard[i].length);
      }
      m_ptMoveChess.x = (e.getX() - BORDERWIDTH) / GRILLEWIDTH;
      m_ptMoveChess.y = (e.getY() - BORDERHEIGHT) / GRILLEHEIGHT;
      m_MoveChess.nChessID = chessBoard[m_ptMoveChess.y][m_ptMoveChess.x];
      chessBoard[m_ptMoveChess.y][m_ptMoveChess.x] = Eveluation.NOCHESS;
      m_MoveChess.ptMovePoint = new Point(e.getX() - 18, e.getY() - 18);
      this.repaint();
    }
  }

  @Override
  public void mouseReleased(MouseEvent e)
  {
    // TODO: Add your message handler code here and/or call default
    boolean bTurnSide = false;
    if (gameOver)
    {
      return;
    }
    long timecount;
    if (m_MoveChess.nChessID != 0
            && MoveGenerator.isValidMove(backupChessBoard, m_ptMoveChess.x, m_ptMoveChess.y,
                    (e.getX() - BORDERWIDTH) / GRILLEWIDTH, (e.getY() - BORDERHEIGHT) / GRILLEHEIGHT))
    {
      chessBoard[(e.getY() - BORDERHEIGHT) / GRILLEHEIGHT][(e.getX() - BORDERWIDTH) / GRILLEWIDTH] = m_MoveChess.nChessID;
      bTurnSide = true;
    } else
    {
      for (int i = 0; i < backupChessBoard.length; i++)
      {
        System.arraycopy(backupChessBoard[i], 0, chessBoard[i], 0, backupChessBoard[i].length);
      }
    }
    m_MoveChess.nChessID = Eveluation.NOCHESS;
    this.repaint();
    if (bTurnSide)
    {
      timecount = System.currentTimeMillis();
      this.se.searchAGoodMove(chessBoard);
      System.out.println("耗时：" + (System.currentTimeMillis() - timecount) + "毫秒" + "   估值" + this.eveluation.count + "个节点");
    }
    if (isGameOver(chessBoard))
    {
      gameOver = true;
      System.out.println("Game Over !");
    }
    this.eveluation.count = 0;
    //this.repaint();
  }

  @Override
  public void mouseEntered(MouseEvent e)
  {
    //throw new UnsupportedOperationException("Not supported yet.");
  }

  @Override
  public void mouseExited(MouseEvent e)
  {
    //throw new UnsupportedOperationException("Not supported yet.");
  }

  @Override
  public void mouseDragged(MouseEvent e)
  {
    //throw new UnsupportedOperationException("Not supported yet.");
  }

  @Override
  public void mouseMoved(MouseEvent e)
  {
    //throw new UnsupportedOperationException("Not supported yet.");
  }
}
